package com.songqi.common.security.auth;


import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.songqi.common.core.exception.user.AccountAuthenticationException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

import java.util.Date;

import static com.songqi.common.core.constant.Constants.YES_FLAG;

/**
 * 短信登陆鉴权 Provider，要求实现 AuthenticationProvider 接口
 *
 * @author gmk
 */
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
        // 获取手机号或邮件地址
        String phone = (String) authentication.getPrincipal();
        UserDetails userDetails = userDetailsService.loadUserByUsername(phone);
        // 获取验证验证码是否正确的必要信息
        SmsCodeCredentials smsCodeCredentials = (SmsCodeCredentials) authentication.getCredentials();
        String inputVerifyCode = smsCodeCredentials.getInputCode();
        // 判断验证码是否正确
        if(! inputVerifyCode.equals(smsCodeCredentials.getVerifyCode())){
            throw new AccountAuthenticationException("验证码不正确");
        }
        // 判断验证码是否过期
        Date createTime = smsCodeCredentials.getCreateTime();
        Date nowTime = new Date();
        long between = DateUtil.between(createTime, nowTime, DateUnit.SECOND);
        if(between > 10 * 60){
            throw new AccountAuthenticationException("验证码已过期");
        }
        // 判断验证码是否使用
        if(smsCodeCredentials.getUseFlag().equals(YES_FLAG)){
            throw new AccountAuthenticationException("请先获取验证码");
        }


        // 此时鉴权成功后，应当重新 new 一个拥有鉴权的 authenticationResult 返回
        SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
        authenticationResult.setDetails(authenticationToken.getDetails());

        return authenticationResult;
    }


    @Override
    public boolean supports(Class<?> authentication) {
        // 判断 authentication 是不是 SmsCodeAuthenticationToken 的子类或子接口
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
}